package chapter21;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;

/**
 * @author lzy
 * @version v1.0
 * Create DateTime: 2019/2/25 17:05
 */
public class GenericDemo {
    public static void main(String[] args) throws Exception {
        SubClass<Integer, String> test = new SubClass();
        System.out.println(test.getVRealClass());
        System.out.println(test.getURealClass());

        Class<?> cls = GenericTest.class;
        //类的类型参数
        for (TypeVariable t : cls.getTypeParameters()) {
            System.out.println(t.getName() + " extends " + Arrays.toString(t.getBounds()));
        }

        //字段：泛型类型
        Field fu = cls.getDeclaredField("u");
        System.out.println(fu.getGenericType());

        //字段：参数化类型
        Field flist = cls.getDeclaredField("list");
        Type listType = flist.getGenericType();
        if (listType instanceof ParameterizedType) {
            ParameterizedType ptype = (ParameterizedType) listType;
            System.out.println("raw type: " + ptype.getRawType() + ", type arguments:" + Arrays.toString(ptype.getActualTypeArguments()));
        }

        //方法的泛型参数
        Method method = cls.getMethod("test", List.class);
        for (Type type : method.getGenericParameterTypes()) {
            System.out.println(type);
        }
    }

    static class GenericTest<U extends Comparable<U>, V> {
        U u;
        V v;
        List<String> list;

        public U test(List<? extends Number> numbers) {
            return null;
        }

        @SuppressWarnings("unchecked")
        Class<U> getURealClass() {
            Type type = getClass().getGenericSuperclass();
            if (type instanceof ParameterizedType) {
                ParameterizedType t = (ParameterizedType) type;
                Type temp = t.getActualTypeArguments()[0];
                if (!"U".equals(temp.getTypeName())) {
                    return (Class<U>) temp;
                }
            }
            return null;
        }

        @SuppressWarnings("unchecked")
        Class<V> getVRealClass() {
            Type type = getClass().getGenericSuperclass();
            if (type instanceof ParameterizedType) {
                ParameterizedType t = (ParameterizedType) type;
                Type typeArgument = t.getActualTypeArguments()[1];
                if (!"V".equals(typeArgument.getTypeName())) {
                    return (Class<V>) t.getActualTypeArguments()[1];
                }
            }
            return null;
        }
    }

    static class SubClass<U extends Comparable<U>, V> extends GenericTest<U, V> {
    }
}
